#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <wiringPi.h>
#include <pthread.h>
#include "uartTool.h"
#include "garbage.h"
#include "pwm.h"
#include "myoled.h"
#include "socket.h"

int serial_fd = -1;
pthread_cond_t cond;
pthread_mutex_t mutex; // 声明一个互斥锁(保障多个进程之间执行时序)

// 检测后台是否有相机进程mjpg
static int detect_process(const char *process_name)
{
    // 初始化变量
    int n = -1;
    FILE *strm;
    char buf[128] = {0};

    // 构造命令行，查找指定名称的进程
    sprintf(buf, "ps -ax | grep %s|grep -v grep", process_name);

    // 执行命令行并获取输出流
    if ((strm = popen(buf, "r")) != NULL)
    {
        // printf("执行命令行完成\n");
        // 读取输出流的第一行，判断进程是否存在
        if (fgets(buf, sizeof(buf), strm) != NULL)
        {
            // printf("进程存在\n");
            n = atoi(buf);
            // printf("n=%d\n", n);
        }
    }
    else
    {
        // 如果无法执行命令行，返回错误码
        return -1;
    }

    // 关闭管道
    pclose(strm);

    // 返回进程的PID，如果没有找到则返回-1
    return n;
}

// 语音模块线程获取识别语音指令
void *pget_voice(void *arg)
{
    unsigned char buffer[6] = {0xAA, 0x55, 0x00, 0x00, 0X55, 0xAA};
    int len = 0;
    printf("%s|%s|%d\n", __FILE__, __func__, __LINE__);
    if (-1 == serial_fd)
    {
        printf("%s|%s|%d: open serial failed\n", __FILE__, __func__, __LINE__);
        pthread_exit(0);
    }
    printf("%s|%s|%d\n", __FILE__, __func__, __LINE__);
    while (1)
    {
        len = serialGetstring(serial_fd, buffer); // 语音模块收到语音指令后会发送46 00,开发板接收串口信息
        printf("%s|%s|%d, len=%d\n", __FILE__, __func__, __LINE__, len);
        if (len > 0 && buffer[2] == 0x46)
        {
            printf("%s|%s|%d\n", __FILE__, __func__, __LINE__);
            pthread_mutex_lock(&mutex);
            /*两个线程并行执行,都对buffer[2]进行写操作因此会出现竞态条件,为解决该问题使用互斥锁;
            另外要保证两个线程执行的时序: 当开发板收到信息并判断为0x46后, 使用pthread_cond_signal()函数
            唤醒正在等待条件信号的线程(alinyu线程)*/
            buffer[2] = 0x00;
            pthread_cond_signal(&cond); // 使用该函数唤醒正在等待条件信号的线程(alinyu线程)
            pthread_mutex_unlock(&mutex);
        }
    }
    pthread_exit(0);
}

void *popen_trash_can(void *arg)
{
    pthread_detach(pthread_self()); // 使得父线程不用去等待子线程，子线程自己去释放资源
    unsigned char *buffer = (unsigned char *)arg;
    if (buffer[2] == 0x43)
    {
        printf("%s|%s|%d: buffer[2]=0x%x\n", __FILE__, __func__, __LINE__,
               buffer[2]);
        pwm_write(PWM_RECOVERABLE_GARBAGE);
        delay(2000);
        pwm_stop(PWM_RECOVERABLE_GARBAGE);
    }
    else if (buffer[2] == 0x41)
    {
        printf("%s|%s|%d: buffer[2]=0x%x\n", __FILE__, __func__, __LINE__,
               buffer[2]);
        pwm_write(PWM_Dry_GARBAGE);
        delay(2000);
        pwm_stop(PWM_Dry_GARBAGE);
    }
    else if (buffer[2] == 0x42)
    {
        printf("%s|%s|%d: buffer[2]=0x%x\n", __FILE__, __func__, __LINE__,
               buffer[2]);
        pwm_write(PWM_Wet_GARBAGE);
        delay(2000);
        pwm_stop(PWM_Wet_GARBAGE);
    }
    else if (buffer[2] == 0x44)
    {
        printf("%s|%s|%d: buffer[2]=0x%x\n", __FILE__, __func__, __LINE__,
               buffer[2]);
        pwm_write(PWM_Hazardous_GARBAGE);
        delay(2000);
        pwm_stop(PWM_Hazardous_GARBAGE);
    }
    pthread_exit(0);
}

void *psend_voice(void *arg) // 语音播报线程
{
    pthread_detach(pthread_self());
    unsigned char *buffer = (unsigned char *)arg;
    if (-1 == serial_fd)
    {
        printf("%s|%s|%d: open serial failed\n", __FILE__, __func__, __LINE__);
        pthread_exit(0);
    }
    if (NULL != buffer)
    {
        serialSendstring(serial_fd, buffer, 6);
    }
    pthread_exit(0);
}

void *poled_show(void *arg)
{
    pthread_detach(pthread_self());
    myoled_init();
    oled_show(arg);
    pthread_exit(0);
}

void *pcategory(void *arg)
{
    unsigned char buffer[6] = {0xAA, 0x55, 0x00, 0x00, 0X55, 0xAA};
    char *category = NULL;
    pthread_t send_voice_tid, trash_tid, oled_tid;
    printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
    while (1)
    {
        printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
        pthread_mutex_lock(&mutex);
        pthread_cond_wait(&cond, &mutex);
        pthread_mutex_unlock(&mutex);
        printf("%s|%s|%d: \n", __FILE__, __func__, __LINE__);
        buffer[2] = 0x00;
        system(WGET_CMD);
        if (0 == access(GARBAGE_FILE, F_OK))
        {
            category = garbage_category(category);
            if (strstr(category, "干垃圾"))
            {
                buffer[2] = 0x41;
            }
            else if (strstr(category, "湿垃圾"))
            {
                buffer[2] = 0x42;
            }
            else if (strstr(category, "可回收垃圾"))
            {
                buffer[2] = 0x43;
            }
            else if (strstr(category, "有害垃圾"))
            {
                buffer[2] = 0x44;
            }
            else
            {
                buffer[2] = 0x45;
            }
        }
        else
        {
            buffer[2] = 0x45;
        }

        // 开语音播报线程
        pthread_create(&trash_tid, NULL, psend_voice, (void *)buffer); // 需要传入参数buffer
        // 开垃圾桶开关
        pthread_create(&send_voice_tid, NULL, popen_trash_can, (void *)buffer); // 需要传入参数buffer
        // oled显示线程
        pthread_create(&oled_tid, NULL, poled_show, (void *)buffer);
        // buffer[2] = 0x00;
        remove(GARBAGE_FILE);
    }
    pthread_exit(0);
}

void *pget_socket(void *arg)
{
    int s_fd = -1;
    int c_fd = -1;
    char buffer[6];
    int nread = -1;
    struct sockaddr_in c_addr; // 声明一个客户端socket
    memset(&c_addr, 0, sizeof(struct sockaddr_in));
    s_fd = socket_init(IPADDR, IPPORT);
    printf("%s|%s|%d:s_fd=%d\n", __FILE__, __func__, __LINE__, s_fd);
    if (-1 == s_fd)
    {
        pthread_exit(0);
    }
    sleep(3);
    int clen = sizeof(struct sockaddr_in);
    while (1)
    {
        c_fd = accept(s_fd, (struct sockaddr *)&c_addr, &clen); // 返回c_fd用来与客户端通信send()/recv()
        printf("%s|%s|%d: Accept a connection from %s:%d\n", __FILE__, __func__, __LINE__, inet_ntoa(c_addr.sin_addr), ntohs(c_addr.sin_port));
        int keepalive = 1; // 开启TCP KeepAlive功能
        int keepidle = 5;  // tcp_keepalive_time 超市时间时间到了开始轮训
        int keepcnt = 3;   // tcp_keepalive_probes 轮训次数
        int keepintvl = 3; // tcp_keepalive_intvl 每次轮训之间的间隔时间
        setsockopt(c_fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepalive,
                   sizeof(keepalive));
        setsockopt(c_fd, SOL_TCP, TCP_KEEPIDLE, (void *)&keepidle, sizeof(keepidle));
        setsockopt(c_fd, SOL_TCP, TCP_KEEPCNT, (void *)&keepcnt, sizeof(keepcnt));
        setsockopt(c_fd, SOL_TCP, TCP_KEEPINTVL, (void *)&keepintvl, sizeof(keepintvl));

        if (c_fd == -1)
        {
            perror("accept");
            continue;
        }
        while (1)
        {
            memset(buffer, 0, sizeof(buffer));
            nread = recv(c_fd, buffer, sizeof(buffer), 0); // n_read = read(c_fd, buffer, sizeof(buffer));

            printf("%s|%s|%d:nread=%d, buffer=%s\n", __FILE__, __func__, __LINE__, nread, buffer);
            if (nread > 0)
            {
                if (strstr(buffer, "open"))
                {
                    pthread_mutex_lock(&mutex);
                    pthread_cond_signal(&cond);
                    pthread_mutex_unlock(&mutex);
                }
            }
            else if (0 == nread || -1 == nread)
            {
                break;
            }
        }
        close(c_fd);
    }
    pthread_exit(0);
}

int main(int argc, char *argv[])
{

    int ret = -1;
    // unsigned char buffer[6] = {0xAA, 0X55, 0x00, 0x00, 0x55, 0xAA};语音线程已定义
    int len = 0;
    char *category = NULL;
    pthread_t get_voice_tid, category_tid, get_socket_tid; // 定义两个线程ID

    wiringPiSetup();
    garbage_init();

    ret = detect_process("mjpg_streamer"); // 用于判断mjpg_streamer服务是否已经启动
    if (-1 == ret)
    {
        printf("detect process failed\n");
        goto END;
    }
    printf("mjpg_streamer open\n");

    serial_fd = myserialOpen(SERIAL_DEV, BAUD); // 打开串口设备(语音模块)
    if (-1 == serial_fd)
    {
        printf("open serial failed\n");
        goto END;
    }
    printf("open serial\n");

    // 开语音线程
    printf("%s|%s|%d\n", __FILE__, __func__, __LINE__);
    pthread_create(&get_voice_tid, NULL, pget_voice, NULL); // 第一个NULL采用默认配置,第二个NULL表示不传参
    // 开网络线程
    pthread_create(&get_socket_tid, NULL, pget_socket, NULL);
    // 开阿里云交互线程
    printf("%s|%s|%d\n", __FILE__, __func__, __LINE__);
    pthread_create(&category_tid, NULL, pcategory, NULL); // 阿里云线程包含三个线程

    pthread_join(get_voice_tid, NULL); // 主线程等待子线程完成
    pthread_join(category_tid, NULL);
    pthread_join(get_socket_tid, NULL);

    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);
    close(serial_fd);

END:
    garbage_final();
    return 0;
}
